-- 地图九宫分区
local GRID_WIDTH  = 800
local GRID_HEIGHT = 600
local OFFSET    = 100
local floor     = math.floor
local Obj = require("core.Obj")
-- 地图格子
-- 注：不计划热更新

function new_grid()
    local none  = {[0]=0}
    local bad = {[0]=0}
    local good  = {[0]=0}
    local view  = {[0]=none, [1]=bad, [2]=good, none = none, bad = bad, good = good}

    local none  = {[0]=0}
    local bad = {[0]=0}
    local good  = {[0]=0}
    return {
        mark=0, parent=nil, col=nil, row=nil,
        [0]=none, [1]=bad, [2]=good,
        none = none, bad = bad, good = good,
        view = view --九宫格显示数据
    }
end



function new_partition(mapWidth, mapHeight)
    return {maxCol=floor(mapWidth/GRID_WIDTH),
    maxRow=floor(mapHeight/GRID_HEIGHT),
}
end

-- type 0:无 1：敌 2：友
function insert(this, obj)
    if obj.map_grid then
        assert()
    end
    local type = obj.camps or 0

    local col = floor(obj.x/GRID_WIDTH)
    local row = floor(obj.y/GRID_HEIGHT)
    if col<0 then
        col = 0
    elseif col>this.maxCol then
        col = this.maxCol
    end

    if row<0 then
        row = 0
    elseif row>this.maxRow then
        row = this.maxRow
    end

    local index = col*OFFSET + row
    local grid  = this[index]
    if not grid then
        grid = new_grid()
        grid.parent = this
        grid.col = col
        grid.row = row
        this[index] = grid
    end
    obj.map_grid  = grid

    if obj.hide or obj.obj_type == Obj.TYPE_AOE then return end --AOE 不被扫描 等...

    local list = grid[type]
    local len  = list[0]+1
    list[len] = obj
    list[0]   = len

    obj.grid_index = len
end

function remove(this, obj)
    if not obj.map_grid then return end
    local grid = obj.map_grid
    local type = obj.camps or 0
    local list = grid[type]
    local len = list[0]
    obj.map_grid = nil
    if list[obj.grid_index] == obj then
        list[obj.grid_index] = list[len]
        list[len] = nil
        list[0] = len-1
        obj.grid_index = nil
        return
    end
    for i = 1, len do
        if list[i] == obj then
            list[i] = list[len]
            list[len] = nil
            list[0] = len -1
            break
        end
    end
    obj.grid_index = nil
end

function update(this, obj)
    local col = floor(obj.x/GRID_WIDTH)
    local row = floor(obj.y/GRID_HEIGHT)
    if col<0 then
        col = 0
    elseif col>this.maxCol then
        col = this.maxCol
    end

    if row<0 then
        row = 0
    elseif row>this.maxRow then
        row = this.maxRow
    end

    local index = col*OFFSET + row
    if obj.map_grid and obj.map_grid == this[index] and obj.grid_index then
        return
    end
    remove(this, obj)
    insert(this, obj)
end


function get_grid(this, x, y)
    local col = floor(x/GRID_WIDTH)
    local row = floor(y/GRID_HEIGHT)
    local index = col*OFFSET + row
    local grid  = this[index]
    return grid
end

function get_grid_index(this, col, row)
    local index = col*OFFSET + row
    local grid  = this[index]
    return grid and grid
end

function get_view(obj)
    local grid = obj.map_grid
    local this = grid.parent
    local view = grid.view

    local beginCol  = grid.col - 1
    local beginRow  = grid.row - 1
    local endCol  = beginCol + 2
    local endRow  = beginRow + 2

    if beginCol<0 then
        beginCol = 0
    elseif beginCol>this.maxCol then
        beginCol = this.maxCol
    end

    if beginRow<0 then
        beginRow = 0
    elseif beginRow>this.maxRow then
        beginRow = this.maxRow
    end

    local noneLen = 0
    local badLen  = 0
    local goodLen = 0

    local none    = view.none
    local bad   = view.bad
    local good    = view.good
    for i=beginCol, endCol do
        for j=beginRow, endRow do
            grid = get_grid_index(this, i, j)
            if grid then
                noneLen = noneLen+1
                none[noneLen] = grid[0]
                badLen = badLen+1
                bad[badLen] = grid[1]
                goodLen = goodLen+1
                good[goodLen] = grid[2]
            end
        end
    end

    none[0]   = noneLen
    bad[0]    = badLen
    good[0]   = goodLen
    return view
end
